<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>集成方式</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="../lib/layui-v2.5.5/css/layui.css" media="all">
    <link rel="stylesheet" href="../lib/font-awesome-4.7.0/css/font-awesome.min.css" media="all">
    <link rel="stylesheet" href="../css/public.css" media="all">
    <style>
        .layui-card {border:1px solid #f2f2f2;border-radius:5px;}
        .icon {margin-right:10px;color:#1aa094;}
        .icon-cray {color:#ffb800!important;}
        .icon-blue {color:#1e9fff!important;}
        .icon-tip {color:#ff5722!important;}
        .layuimini-qiuck-module {text-align:center;margin-top: 10px}
        .layuimini-qiuck-module a i {display:inline-block;width:100%;height:60px;line-height:60px;text-align:center;border-radius:2px;font-size:30px;background-color:#F8F8F8;color:#333;transition:all .3s;-webkit-transition:all .3s;}
        .layuimini-qiuck-module a cite {position:relative;top:2px;display:block;color:#666;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;font-size:14px;}
        .welcome-module {width:100%;height:210px;}
        .panel {background-color:#fff;border:1px solid transparent;border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}
        .panel-body {padding:10px}
        .panel-title {margin-top:0;margin-bottom:0;font-size:12px;color:inherit}
        .label {display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;margin-top: .3em;}
        .layui-red {color:red}
        .main_btn > p {height:40px;}
        .layui-bg-number {background-color:#F8F8F8;}
        .layuimini-notice:hover {background:#f6f6f6;}
        .layuimini-notice {padding:7px 16px;clear:both;font-size:12px !important;cursor:pointer;position:relative;transition:background 0.2s ease-in-out;}
        .layuimini-notice-title,.layuimini-notice-label {
            padding-right: 70px !important;text-overflow:ellipsis!important;overflow:hidden!important;white-space:nowrap!important;}
        .layuimini-notice-title {line-height:28px;font-size:14px;}
        .layuimini-notice-extra {position:absolute;top:50%;margin-top:-8px;right:16px;display:inline-block;height:16px;color:#999;}
    </style>
</head>
<body>
<div class="layuimini-container">

    <div class="layui-card">
        <div class="layui-card-header">工作流集成模块简介</div>
        <div class="layui-card-body">
            <p>工作流集成模块旨在提供一个开箱即用的解决方案，简化用户在工作流创建和管理中的复杂性。该模块不需要用户关心底层工作流的启动，创建，分配，执行审批，审批拒绝，审批通过等处理极大减少了初始使用门槛。</p>
        </div>
    </div>
    <div class="layui-card">
        <div class="layui-card-header">主要功能</div>
        <div class="layui-card-body">
            <p><b>开箱即用:</b></p> 用户在引入模块后，无需进行复杂的配置或数据库表结构创建，即可开始使用工作流功能。

            <p><b>事件订阅接口:</b></p> 模块内置接口，允许用户订阅各种节点事件。这意味着用户不再需要单独进行事件监听，简化了工作流的实现过程。

            <p><b>流程部署管理:</b></p> 提供用户友好的界面，方便进行流程的部署与管理。用户可以快速上手，进行流程的版本管理和发布操作。

            <p><b>流程查看:</b></p> 允许用户实时查看当前的工作流状态，帮助用户随时掌握流程进展，提升管理效率。

            <p><b>任务管理:</b></p> 集成任务管理功能，用户可以方便地查看、分配和跟踪任务，确保每个环节的顺利进行。

            <p><b>历史任务管理:</b></p> 记录每个任务的历史执行情况，让用户能够随时回溯，分析和优化工作流程。
        </div>
    </div>

    <div class="layui-collapse" lay-accordion>
        <div class="layui-colla-item">
            <h2 class="layui-colla-title">实现核心接口IActivitiCoreService</h2>
            <div class="layui-colla-content">
                <p>
                    该接口主要是用于角色分配和用户鉴权及用户查询，工作流模块会通过该接口与业务系统进行交互，获取用户信息，角色信息等。
                </p>
                <pre class="layui-code">
@Service
public class ActivitiCoreService implements IActivitiCoreService {

    @Autowired
    private UserService userService;

    @Override
    public AuthConfigServer authConfigServer() {
        return new AuthConfigServer() {
            @Override
            public List<AuthConfigServer.User> users(User user) {
                return userService.users().stream().map(t->new AuthConfigServer.User(t.getUsername(),t.getRealName(),t.getRoles().stream().map(t2->t2.getCode()).collect(Collectors.toList()))).collect(Collectors.toList());
            }

            @Override
            public AuthConfigServer.User username(String username) {
                vo.web.demos.com.easy.demo.User user = userService.byUserName(username);
                if(user!=null){
                    return new AuthConfigServer.User(user.getUsername(),user.getRealName(),user.getRoles().stream().map(t2->t2.getCode()).collect(Collectors.toList()));
                }
                return null;
            }

            @Override
            public User loginUser() {
                vo.web.demos.com.easy.demo.User user =  userService.me();
                if(user!=null){
                    return new AuthConfigServer.User(user.getUsername(),user.getRealName(),user.getRoles().stream().map(t2->t2.getCode()).collect(Collectors.toList()));
                }
                return null;
            }
            @Override
            public List<Org> orgs(Org org) {
                return null;
            }
        };
    }
}
                </pre>
            </div>
        </div>
    </div>
    <div class="layui-collapse" lay-accordion>
        <div class="layui-colla-item">
            <h2 class="layui-colla-title">实现工作流监听接口IActivitiListener</h2>
            <div class="layui-colla-content">
                <p>
                    该接口对应一个工作流，通过实现的方法可以做监听启动，完成，分配，拒绝，结束等流程节点，然后对业务做出相应的修改
                </p>
                <pre class="layui-code">
    /**
     * 流程启动
     * @param taskEvent
     */
    default void processStarted(TaskEvent taskEvent){
        System.out.println("processStarted called:"+taskEvent.getBusinessKey());
    }
    /**
     * 初始化启动变量
     */
    default Map<String,Object> startVariables(){
        System.out.println("startVariables");
        return new HashMap<>();
    }
    /**
     * 审批拒绝
     * @param taskEvent
     */
    default void reject(TaskEvent taskEvent){
        System.out.println("reject called:"+taskEvent.getBusinessKey());
    }
    /**
     * 任务创建，可以分配人员
     * @param taskEvent
     */
    default void created(TaskEvent taskEvent){
        System.out.println("created called:"+taskEvent.getBusinessKey());
    }
    /**
     * 任务完成
     * @param taskEvent
     */
    default void complete(TaskEvent taskEvent){
        System.out.println("complete called:"+taskEvent.getBusinessKey());
    }
    /**
     * 任务分配
     * @param taskEvent
     */
    default void assigned(TaskEvent taskEvent){
        System.out.println("assigned called:"+taskEvent.getBusinessKey());
    }
    /**
     * 流程结束，审批通过
     * @param taskEvent
     */
    default void processComplete(TaskEvent taskEvent){
        System.out.println("processComplete called:"+taskEvent.getBusinessKey());
    }
                </pre>
                <p>接入方式</p>
                <pre class="layui-code">
@OnActivitiEvent(value = "TravelApplication") //TravelApplication为工作流对应的Key,告诉系统需要监听哪个工作流
@Service
public class DemoActivitiService implements IActivitiListener
                </pre>
            </div>
        </div>
    </div>
    <div class="layui-collapse" lay-accordion>
        <div class="layui-colla-item">
            <h2 class="layui-colla-title">设置审核人员</h2>
            <div class="layui-colla-content">
                <p>通过实现接口IActivitiListener，覆盖startVariables方法，此方法可以为流程启动时候注入所有需要的变量</p>
                <pre class="layui-code">
    @Override
    public Map<String, Object> startVariables() {
        return new HashMap<String,Object>(){{
                     put("hr","zhangsan");
                     put("manager","lisi");
                     put("ceo","zhouchuang");
                     put("day",2);
                     }};
    }
    //此处的hr ，manager，ceo 为请假申请工作流，配置在候选用户中，格式为${hr}，${manager}，${ceo}。day 可以是流程里面配置的任何变量，此处为请假天数，为条件控制变量
                </pre>
                <p>通过实现接口IActivitiListener，覆盖created方法，此方法可以在每个节点创建前调用，可以在此为各个节点分配审核人员，或注入变量</p>
                <pre class="layui-code">
    @Override
    public void created(TaskEvent taskEvent) {
        if(taskEvent.getTaskEntity().getName().equals("人事审批")||taskEvent.getTaskEntity().getName().equals("财务审批")){
            taskEvent.setAssignee("zhangsan");
        }
    }

    //该方法在创建任务的时候触发，此处分别为人事审批节点，和财务审批节点分配审批人
                </pre>
                <p>通过OnActivitiEvent注解更精确监听某个节点某个方法，以下还是以分配审核人员举例</p>
                <pre class="layui-code">

    @OnActivitiEvent(type = OnActivitiEvent.Type.TASK_CREATED,name = "经理审批")
    public void setManager(TaskEvent taskEvent) {
        taskEvent.setAssignee("zhouchuang");
    }
    //该方法在流程节点为 经理审批 节点事件类型为 任务创建的时候 触发，此处为经理审批分配审核人员为 zhouchuang
                </pre>

            </div>
        </div>
        <div class="layui-colla-item">
            <h2 class="layui-colla-title">设置变量</h2>
            <div class="layui-colla-content">
                <p>任何节点的任何事件，都可以设置变量</p>

                <pre class="layui-code">
    @OnActivitiEvent(type = OnActivitiEvent.Type.TASK_CREATED,name = "人事审批")
    public void setmanager(TaskEvent taskEvent) {
        taskEvent.setAssignee("zhouchuang");
        taskEvent.getTaskEntity().setVariables(new HashMap<String,Object>(){{put("day",2);}});
    }
    //通过taskEvent.getTaskEntity().setVariables()方法可以设置后续审批节点需要的动态变量
                </pre>
            </div>
        </div>
        <div class="layui-colla-item">
            <h2 class="layui-colla-title">监听流程启动</h2>
            <div class="layui-colla-content">
                <p>通常我们会在流程启动的时候，需要修改业务数据的审批状态为，审批中，我们可以实现</p>

                <pre class="layui-code">
    @Override
    public void processStarted(TaskEvent taskEvent){
        //改成审批中
        Leave leave = leaveService.get(taskEvent.getBusinessKey());
        leave.setStatus(Leave.Status.APPROVING.getCode()); //需改状态为审批中
        leave.setInstId(taskEvent.getProcessInstanceId()); //同时保存好实例id到业务数据中，方便业务数据可以直接查看审批流程
        leaveService.update(leave);
    }
    //此处可以通过taskEvent.getBusinessKey()方法获取业务ID，该ID是流程启动时候传递到工作流的
                </pre>
            </div>
        </div>

        <div class="layui-colla-item">
            <h2 class="layui-colla-title">监听流程拒绝</h2>
            <div class="layui-colla-content">
                <p>通常我们会在流程审批拒绝的时候，需要修改业务数据的审批状态为，审批拒绝</p>

                <pre class="layui-code">
    @Override
    public  void reject(TaskEvent taskEvent) {
        Leave leave = leaveService.get(taskEvent.getBusinessKey());  //通过taskEvent.getBusinessKey()获取对应的业务数据
        leave.setStatus(Leave.Status.REJECT.getCode());  //修改状态为拒绝
        leaveService.update(leave);
    }
                </pre>
            </div>
        </div>


        <div class="layui-colla-item">
            <h2 class="layui-colla-title">监听流程完成审批通过</h2>
            <div class="layui-colla-content">
                <p>在流程审批完成时，需要修改业务数据的审批状态为，审批通过，并且此处可以做业务数据下一步流转</p>
                <pre class="layui-code">
    @Override
    public void processComplete(TaskEvent taskEvent) {
        //流程走完，改成审批通过
        Leave leave = leaveService.get(taskEvent.getBusinessKey());
        leave.setStatus(Leave.Status.PASS.getCode());
        leaveService.update(leave);
    }
                </pre>
            </div>
        </div>

        <div class="layui-colla-item">
            <h2 class="layui-colla-title">业务系统中启动工作流</h2>
            <div class="layui-colla-content">
                <p>在流程审批完成时，需要修改业务数据的审批状态为，审批通过，并且此处可以做业务数据下一步流转</p>
                <pre class="layui-code">
    请求路径：http://localhost:8081/activiti/startProcess
    请求方法：POST
    请求参数：
            processDefinitionKey: TravelApplication  //对应工作流Key
            instanceName: 周创出差申请                 //对应流程实例的名称
            businessKey: 123456                      //对应业务系统的ID，后需审批过程中可以通过此ID对业务数据修改
                </pre>
            </div>
        </div>
    </div>

</div>
<script src="https://cdn.jsdelivr.net/npm/layui-src/dist/layui.all.js"></script>
<script>

</script>
</body>
</html>
